package com.bot.telegramvariousbot.service.telegram.bot;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bot.telegramvariousbot.dao.LuckDrawDaoExt;
import com.bot.telegramvariousbot.model.TgDraw;
import com.bot.telegramvariousbot.model.TgDrawActivity;
import com.bot.telegramvariousbot.model.TgDrawRecord;
import com.bot.telegramvariousbot.service.telegram.config.LuckDrawConfig;
import com.bot.telegramvariousbot.utils.DateUtil;
import com.bot.telegramvariousbot.utils.IDGen;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.telegram.telegrambots.bots.DefaultBotOptions;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.methods.updatingmessages.DeleteMessage;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;

import java.util.*;
import java.util.regex.Pattern;

public class LuckDrawBot extends TelegramLongPollingBot {

    private static Logger logger = LoggerFactory.getLogger(LuckDrawBot.class);

    private LuckDrawDaoExt luckDrawDaoExt;

    private CloseableHttpClient closeableHttpClient;

    private WebClient webClient;

    DeleteMessage dm = null;

    public LuckDrawBot(WebClient webClient,CloseableHttpClient closeableHttpClient,LuckDrawDaoExt luckDrawDaoExt,DefaultBotOptions options) {
        super(options);
        this.closeableHttpClient = closeableHttpClient;
        this.luckDrawDaoExt = luckDrawDaoExt;
        this.webClient = webClient;
    }

    public LuckDrawBot() {
        this((DefaultBotOptions) new DefaultBotOptions());
    }

    public LuckDrawBot(DefaultBotOptions options) {
        super(options);
    }

    public void onUpdateReceived(Update update) {
        SendMessage message = null;
        if(ObjectUtils.isEmpty(update)){
            return;
        }
        logger.info("LuckDrawBot 新消息：update！= null");
        if (update.getMessage() != null) {
            //欢迎新成员
            if (update.getMessage().getText() == null) {
                //临时注释新成员欢迎语
//                if (update.getMessage().getNewChatMembers() != null) {
//                    if (update.getMessage().getNewChatMembers().size() != 0) {
//                        message = new WelcomeMessage().welcomeMember(update);
//                    }
//                }
            } else {
                if (update.getMessage().getEntities() != null) {
                    if (update.getMessage().getEntities().size() > 0) {
                        if (update.getMessage().getEntities().get(0).getType().equals("bot_command")) {//判断是否是命令
                            String commandText = update.getMessage().getText().toLowerCase().replace("@" + LuckDrawConfig.BOOT_NAME_TEXT, "").trim();

                            if (commandText.equalsIgnoreCase(LuckDrawConfig.START)) {    //判断是否是开始命令
                                message = getHlepMsg(update);
                            } else if (commandText.equalsIgnoreCase(LuckDrawConfig.HELP)) {
                                message = getHlepMsg(update);
                            }else if (commandText.equalsIgnoreCase(LuckDrawConfig.DRAW)) {
                                message = getDarwMsg(update);
                            }else if (commandText.equalsIgnoreCase(LuckDrawConfig.LOTTERY)) {
                                message = getLotteryMsg(update);
                            }
                        }
                    }
                }

            }
        } else if (update.getCallbackQuery() != null) {
            logger.info("update.getCallbackQuery() != null");
            message = getCallBackDarwMsg(update);
        } else {
            logger.info("LuckDrawBot msg unkown");
        }


        try {
            if (message != null) {
                execute(message);
                message = null;
            }
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }


    }

    public String getBotUsername() {
        return  LuckDrawConfig.BOOT_NAME_TEXT;
    }

    public String getBotToken() {
        return LuckDrawConfig.TOKEN_TEXT;
    }

    public SendMessage getHlepMsg(Update update){
        SendMessage message = new SendMessage();
        //message.setText("\uD83D\uDD25<b>Lucky Draw</b>\uD83D\uDD25\n\n\uD83C\uDF81To celebrate the partnership between @Crypto60sec and @karastargamefi, At the end of November, we will randomly select 2 users to grant:\n\n\uD83D\uDCB0 <b>1 ,000,000  SHIB +100 Umy+ 10,000 Seccoin</b>\\n\\n\uD83D\uDCCD<b><em>Lucky draw rules</em></b>\uD83D\uDCCD\n<em>Participants will receive an 8-digit lottery code, and the administrator will draw the lottery immediately after the event.\uD83E\uDD29</em>\n<em>The robot takes the most recent Ethereum block and compares it with the participants' drawing codes in order of eight digits. The two with the smallest difference will win the prize.\uD83E\uDD73</em>\\n\\n\uD83D\uDCCDDraw the time\uD83D\uDCCD\\nFirst time: Nov. 29th 10:00 AM (UTC+0).\nSecond time: Nov. 30th 10:00 AM (UTC+0).</em></b>)\n\n❤️If you are on the reward list, please contact the admin as soon as possible.");
        //
        StringBuilder text = new StringBuilder();
        text.append("\uD83D\uDD25<b>Lucky Draw</b>\uD83D\uDD25");
        text.append("\n\n");
        text.append("\uD83C\uDF81To celebrate the partnership between @Crypto60sec and @karastargamefi, At the end of November, we will randomly select 2 users to grant:");
        text.append("\n\n\uD83D\uDCB0 <b>1 ,000,000  SHIB +100 Umy+ 10,000 Seccoin</b>");
        text.append("\n\n\uD83D\uDCCD<b><em>Lucky draw rules</em></b>");
        text.append("\uD83D\uDCCD\n<em>Participants will receive an 8-digit lottery code, and the administrator will draw the lottery immediately after the event.\uD83E\uDD29</em>\n<em>The robot takes the most recent Ethereum block and compares it with the participants' drawing codes in order of eight digits. The two with the smallest difference will win the prize.\uD83E\uDD73</em>");
        text.append("\n\n\uD83D\uDCCD<b><em>Draw the time</em></b>\uD83D\uDCCD\nFirst time: Nov. 29th 10:00 AM (UTC+0).\nSecond time: Dec. 2nd 10:00 AM (UTC +0).)\n\n");
        text.append("❤️If you are on the reward list, please contact the admin as soon as possible.");
        message.setText(text.toString());
        message.setParseMode("HTML");
        message.disableWebPagePreview();
        message.setChatId(update.getMessage().getChatId().toString());
        //
        List<InlineKeyboardButton> row1 = new ArrayList<InlineKeyboardButton>();
        InlineKeyboardButton keyButton = new InlineKeyboardButton();
        keyButton.setText("draw");
        keyButton.setCallbackData("/draw");
        row1.add(keyButton);

        List<List<InlineKeyboardButton>> backInlineKeyboardButtonList = new ArrayList<List<InlineKeyboardButton>>();
        backInlineKeyboardButtonList.add(row1);
        InlineKeyboardMarkup markUp = new InlineKeyboardMarkup(backInlineKeyboardButtonList);
        message.setReplyMarkup(markUp);
        return message;
    }

    public SendMessage getDarwMsg(Update update){
        SendMessage message = new SendMessage();
        String chatId = update.getMessage().getChatId().toString();
        User user = update.getMessage().getFrom();
        long tgUid = user.getId();
        String userName = "";
        if(StringUtils.isNotBlank(user.getUserName())){
            userName="@"+user.getUserName();
        }else{
            String firstName = user.getFirstName();
            String lastName = user.getLastName();
            if(StringUtils.isNotBlank(lastName)){
                userName=firstName+" "+lastName;
            }else{
                userName=firstName;
            }
        }

        if(StringUtils.isNotBlank(userName)){
            String msg = doDrawActivity(userName,tgUid+"");
            if(StringUtils.isNotBlank(msg)){
                message.setText(msg);
                message.setParseMode("HTML");
                message.disableWebPagePreview();
                message.setChatId(chatId);
                return message;
            }else{
                return null;
            }
        }

        return null;
    }

    public SendMessage getCallBackDarwMsg(Update update){
        if (update == null) {
            return null;
        }
        SendMessage message = new SendMessage();
        String chatId = update.getCallbackQuery().getMessage().getChatId().toString();

        String data = update.getCallbackQuery().getData();
        //Exchange Seccoin
        if (data.equalsIgnoreCase(LuckDrawConfig.DRAW)) {
            User user = update.getCallbackQuery().getFrom();
            long tgUid = user.getId();
            String userName = "";
            if(StringUtils.isNotBlank(user.getUserName())){
                userName="@"+user.getUserName();
            }else{
                String firstName = user.getFirstName();
                String lastName = user.getLastName();
                if(StringUtils.isNotBlank(lastName)){
                    userName=firstName+" "+lastName;
                }else{
                    userName=firstName;
                }
            }
            if(StringUtils.isNotBlank(userName)){
                String msg = doDrawActivity(userName,tgUid+"");
                if(StringUtils.isNotBlank(msg)){
                    message.setText(msg);
                    message.setParseMode("HTML");
                    message.disableWebPagePreview();
                    message.setChatId(chatId);
                    return message;
                }else{
                    return null;
                }
            }
        }
        return null;
    }

    public String doDrawActivity(String username,String tgUid){

        if(StringUtils.isBlank(username)||StringUtils.isBlank(tgUid)){
            return null;
        }
        //活动时间限制
        TgDrawActivity tgDrawActivity = luckDrawDaoExt.getTgDrawById(1);
        if(tgDrawActivity==null){
            return null;
        }
        long time = System.currentTimeMillis();
        long start = tgDrawActivity.getStartTime().getTime();
        long end = tgDrawActivity.getEndTime().getTime();
        if(time<=start){
            return getDrawStartString(start);
        }
        if(time>=end){
            return getDrawEndString();
        }
        //参与限制
        if(isAminds(username)){
            return getAdminString();
        }
        if(isDrawAminds(username)){
            return getAdminString();
        }
        if(isNotJoinIDs(username,tgUid)){
            return getNotJoinString();
        }
        //是否参加
        TgDrawRecord tgDrawRecord = luckDrawDaoExt.getTgDrawRecordByTgUid(tgUid);
        if(tgDrawRecord==null){
            //生成code
            long code = Long.valueOf(IDGen.generateRandomNumberNOTZERO(8));
            TgDrawRecord record = new TgDrawRecord();
            record.setCode(code);
            record.setTgUid(tgUid);
            record.setUserName(username);
            record.setNote("");
            int i = luckDrawDaoExt.insertTgDrawRecordBean(record);
            if(i==1){
                return getDrawCodeString(username,code,end);
            }else{
                return null;
            }
        }else{
            return getRepeatDrawString(username,tgDrawRecord.getCode(),end);
        }

    }

    public SendMessage getLotteryMsg(Update update){
        SendMessage message = new SendMessage();
        String chatId = update.getMessage().getChatId().toString();
        User user = update.getMessage().getFrom();
        long tgUid = user.getId();
        String userName = "";
        if(StringUtils.isNotBlank(user.getUserName())){
            userName="@"+user.getUserName();
        }else{
            String firstName = user.getFirstName();
            String lastName = user.getLastName();
            if(StringUtils.isNotBlank(lastName)){
                userName=firstName+" "+lastName;
            }else{
                userName=firstName;
            }
        }

        if(StringUtils.isNotBlank(userName)){
            String msg = doLotteryActivity(userName,tgUid+"");
            if(StringUtils.isNotBlank(msg)){
                message.setText(msg);
                message.setParseMode("HTML");
                message.disableWebPagePreview();
                message.setChatId(chatId);
                return message;
            }else{
                return null;
            }
        }
        return null;
    }

    public String doLotteryActivity(String username,String tgUid){
        if(StringUtils.isBlank(username)||StringUtils.isBlank(tgUid)){
            return null;
        }
        if(isDrawAminds(username)){
            //活动时间限制
            TgDrawActivity tgDrawActivity = luckDrawDaoExt.getTgDrawById(1);
            if(tgDrawActivity==null){
                return null;
            }
            long time = System.currentTimeMillis();
            long start = tgDrawActivity.getStartTime().getTime();
            long end = tgDrawActivity.getEndTime().getTime();
            if(start<time&&time<end){
                return getLotteryNotYetString();
            }

            TgDraw lotteryRecord = luckDrawDaoExt.getTgDrawLimitOne();
            if(lotteryRecord!=null){
                return getAlreadyLotteryString(lotteryRecord);
            }
            String db_height = tgDrawActivity.getHeight();
            String db_hash = tgDrawActivity.getBlockHash();
            long lottery_time = tgDrawActivity.getLotteryTime().getTime();

            //查询最近高度
            //String height = db_height;
            JSONObject BlockInfo = getYitaifangBlockHash();
            if(BlockInfo==null){
                return null;
            }
            logger.info("BlockInfo:"+BlockInfo.toString());
            String Yitaifang_hash = BlockInfo.getString("hash");
            String Yitaifang_height = BlockInfo.getString("number");
            long Yitaifang_time = BlockInfo.getLongValue("timestamp")*1000;
            String height = Yitaifang_height;
            if(StringUtils.isNotBlank(height)){
                //拿取hash
                //String hash = db_hash;
                //long opentime = lottery_time;
                String hash = Yitaifang_hash;
                long opentime = Yitaifang_time;
                if(StringUtils.isNotBlank(hash)){
                    long drawCode = getHashLong(hash);
                    if(drawCode>0){
                        //中奖人员
                        TgDrawRecord drawRecord = luckDrawDaoExt.getTgDrawRecordByDrawCode(drawCode);
                        if(drawRecord!=null){
                            TgDraw tgDraw = new TgDraw();
                            tgDraw.setBlock(hash);
                            tgDraw.setBlockHeight(height);
                            tgDraw.setBlockCode(drawCode);
                            tgDraw.setOpenTime(opentime);
                            tgDraw.setDrawCode(drawRecord.getCode());
                            tgDraw.setDrawTgUid(drawRecord.getTgUid());
                            tgDraw.setUserName(drawRecord.getUserName());
                            tgDraw.setNote("");
                            int i = luckDrawDaoExt.insertTgDrawBean(tgDraw);
                            if(i==1){
                                //
                                return getLotteryCodeString(drawRecord.getUserName(),drawRecord.getCode(),hash,height,opentime);
                            }else{
                                return null;
                            }
                        }else{
                            return null;
                        }
                    }else{
                        return null;
                    }
                }else{
                    return null;
                }

            }else{
                return null;
            }
        }else{
            return null;
        }
    }

    public static String getDrawStartString(long start){
        //String data = "Draw will begin at 10:00 AM (UTC+0)!";
        Date date = new Date(start);
        String dateStr = DateUtil.parseDateToTGEnStr(date);
        String data = "Draw will begin at " + dateStr+"!";
        return data;
    }

    public static String getDrawEndString(){
        String data = "The lottery is over!";
        return data;
    }
    public static String getAdminString(){
        String data = "You are an administrator.";
        return data;
    }

    public static String getLotteryNotYetString(){
        String data = "The lottery draw is not over yet. Failed to obtain lottery results!";
        return data;
    }

    public static String getNotJoinString(){
        String data = "Congratulations on winning the first draw, the second round of lucky draw is temporarily unavailable.";
        return data;
    }

    public static String getDrawCodeString(String name,long code,long end){
        Date date = new Date(end);
        String dateStr = DateUtil.parseDateToTGEnStr(date);
        String data = "Hi "+name+"\n\nYou have entered the lucky draw and your lucky draw code is <b><em>"+code+"</em></b>.We will draw at "+dateStr+".\n\uD83C\uDF89Good luck!\uD83C\uDF89";
        return data;
    }

    public static String getRepeatDrawString(String name,long code,long end){
        Date date = new Date(end);
        String dateStr = DateUtil.parseDateToTGEnStr(date);
        String data = "Hi "+name+"\n\nPlease do not repeat the drawing since you  getting your draw code <b><em>"+code+"</em></b>.The drawing will be "+dateStr+".\n❤️Stay tuned!❤️";
        return data;
    }

    public static String getLotteryCodeString(String name,long code,String hash,String h,long time){
        Date date = new Date(time);
        String dateStr = DateUtil.parseDateToTGEnStr(date);
        String data = "Hi there, Congrats! "+name+"\n\n"+name+" draw number "+code+"\n\nThe closest to the Ethereum block at "+dateStr+":<em><a href='https://etherscan.io/block/"+h+"'>"+hash+"</a></em>\n\nYou win the reward\n\nThe administrator(@Doris_official1) will contact you.";
        return data;
    }

    public static String getAlreadyLotteryString(TgDraw lotteryRecord){
        //Date date = new Date(lotteryRecord.getOpenTime());
        //String dateStr = DateUtil.parseDateToTGEnStr(date);
        //String name = lotteryRecord.getUserName();
        //String hash = lotteryRecord.getBlock();
        //long code = lotteryRecord.getDrawCode();
        //String h =lotteryRecord.getBlockHeight();
        //String data = "Congrats! "+name+"\n\n"+name+" draw number "+code+"\n\nThe closest to the Ethereum block at "+dateStr+":<em><a href='https://etherscan.io/block/"+h+"'>"+hash+"</a></em>\n\nYou win the reward\n\nThe administrator(@Doris_official1) will contact you.";
        String data = "The result is out !!";
        return data;
    }

    public static boolean isAminds(String userName){
        List<String> adminsList = Arrays.asList(LuckDrawConfig.tg_admins);
        if (adminsList.contains(userName)) {
            return true;
        }
        return false;
    }

    public static boolean isDrawAminds(String userName){
        List<String> adminsList = Arrays.asList(LuckDrawConfig.draw_admin_user);
        if (adminsList.contains(userName)) {
            return true;
        }
        return false;
    }

    public static boolean isNotJoinIDs(String userName,String tgUid){
        List<String> idsList = Arrays.asList(LuckDrawConfig.not_join_ids);
        if (idsList.contains(tgUid)) {
            return true;
        }
        return false;
    }

    public static boolean isContantBannedWords(String text) {
        if (text == null) {
            return false;
        }
        String[] words = text.split(" ");
        for (String word : words) {
            List<String> bannedWordsList = Arrays.asList(LuckDrawConfig.BANNED_WORDS);
            if (bannedWordsList.contains(word)) {
                return true;
            }
        }
        return false;
    }

    public String getBlockHash(){
        try {
            Map<String,String> param = new LinkedHashMap<>();
            String url="https://api.etherscan.io/api?";
            //module=block&action=getblocknobytime&timestamp="+timestamp+"&closest=before&apikey=YourApiKeyToken
            param.put("module","block");
            param.put("action", "getblocknobytime");
            param.put("timestamp", System.currentTimeMillis()/1000+"");
            param.put("closest", "before");
            param.put("apikey", "YourApiKeyToken");

            for (Map.Entry<String,String> m : param.entrySet()) {
                url=url+m.getKey()+"="+m.getValue()+"&";
            }
            HttpGet httpGet = new HttpGet(url);
            HttpResponse response = closeableHttpClient.execute(httpGet);
            if (response.getStatusLine().getStatusCode() == 200) {
                String res = EntityUtils.toString(response.getEntity());
                if (res != null) {
                    JSONObject jsonObject = JSONObject.parseObject(res);
                    if(jsonObject!=null){
                        String re = jsonObject.getString("result");
                        logger.info("getBlockHash:"+re);
                        return re;
                    }else{
                        return null;
                    }
                }else{
                    return null;
                }
            } else {
                logger.info("getBlockHash http failed {},{}", response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
                String res = EntityUtils.toString(response.getEntity());
                logger.info("getBlockHash："+res);
                return null;
            }

        }catch (Exception e){
            logger.error("getBlockHash is error",e);
            return null;
        }

    }

    public String getHash(String height){
        try {
            HtmlPage page = null;
            try {
                String url ="https://etherscan.io/block/"+height;
                page = webClient.getPage(url);//尝试加载上面图片例子给出的网页
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                webClient.close();
            }

            //webClient.waitForBackgroundJavaScript(30000);//异步JS执行需要耗时,所以这里线程要阻塞30秒,等待异步JS执行结束

            String pageXml = page.asXml();//直接将加载完成的页面转换成xml格式的字符串
            //常规的爬虫操作,用到了比较好用的Jsoup库
            Document document = Jsoup.parse(pageXml);//获取html文档
            List<Element> infoListEle = document.select( "div#collapsePanel");//获取元素节点等
            logger.info("getHash infoListEle:"+infoListEle.size());
            if(infoListEle!=null&&infoListEle.size()>0){
                String data = infoListEle.get(0).select("div").first().text();
                logger.info("getHash data:"+data);
                if(data.length()>80){
                    return data.substring(6,72);
                }
            }
            return null;
        }catch (Exception e){
            logger.error("getHash is error",e);
            return null;
        }
    }
    public long getHashLong(String hash){
        try {
            String data = hash.substring(2,hash.length());
            String result="";
            for (int i = 0; i < data.length(); i++) {
                String per = data.substring(i, i + 1);
                if(isInteger(per)){
                    int num = Integer.valueOf(per);
                    if(num>=0&&num<=9){
                        if(result.length()==8){
                            break;
                        }
                        if(result.length()==0&&num==0){
                            continue;
                        }
                        result=result+num;
                    }
                }
            }
            long result_num = Long.valueOf(result);
            return result_num;
        }catch (Exception e){
            logger.error("getHashLong is error",e);
            return 0;
        }

    }

    //网站 https://www.yitaifang.com/blocks/
    public JSONObject getYitaifangBlockHash(){
        try {
            Map<String,String> param = new LinkedHashMap<>();
            String url="https://api.yitaifang.com/index/headers/?";
            param.put("page","1");

            for (Map.Entry<String,String> m : param.entrySet()) {
                url=url+m.getKey()+"="+m.getValue()+"&";
            }
            HttpGet httpGet = new HttpGet(url);
            HttpResponse response = closeableHttpClient.execute(httpGet);
            if (response.getStatusLine().getStatusCode() == 200) {
                String res = EntityUtils.toString(response.getEntity());
                if (res != null) {
                    JSONObject jsonObject = JSONObject.parseObject(res);
                    if(jsonObject!=null){
                        boolean status = jsonObject.getBoolean("status");
                        int code = jsonObject.getIntValue("code");
                        if(status==true&&code==10000){
                            JSONObject data = jsonObject.getJSONObject("data");
                            JSONArray result = data.getJSONArray("result");
                            if(result!=null&&result.size()>0){
                                JSONObject BlockInfo = result.getJSONObject(0);
                                return BlockInfo;
                            }
                        }
                        return null;
                    }else{
                        return null;
                    }
                }else{
                    return null;
                }
            } else {
                logger.info("getBlockHash http failed {},{}", response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
                String res = EntityUtils.toString(response.getEntity());
                logger.info("getBlockHash："+res);
                return null;
            }

        }catch (Exception e){
            logger.error("getBlockHash is error",e);
            return null;
        }

    }

    public static void main(String[] args) {
        String hash = "0xfbe68808aae84a4881656f52d40c46d03a384d96013df6ee318d7183b3500b38";
        String data = hash.substring(2,hash.length());
        String result="";
        for (int i = 0; i < data.length(); i++) {
            String per = data.substring(i, i + 1);
            if(isInteger(per)){
                int num = Integer.valueOf(per);
                if(num>=0&&num<=9){
                    if(result.length()==8){
                        break;
                    }
                    if(result.length()==0&&num==0){
                        continue;
                    }
                    result=result+num;
                }
            }

        }
        System.out.println(result);

    }

    public static boolean isInteger(String str) {
        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
        return pattern.matcher(str).matches();
    }
}